﻿using _12_Reflection;
using System.Reflection;
// 反射 运行时(动态)获取对象的类型 修改其内容 调用其方法 生产新的对象
// 特性 为类提供元数据,行为,注解或标签

//Console.WriteLine(typeof(Test2).GetType());

People people = new People("张三", 19);
//Console.WriteLine(Serialize(people));

Item item = new Item(1, "道具", "介绍") { a = 1 ,b = 2};  // 为没有构造的属性额外赋值
Console.WriteLine(Serialize(item));
Console.WriteLine(item.Id);

//Test(1,c:3);
//void Test(int a,int b = 1,int c = 2)
//{

//}

// 判断类型是否一致 通过typeof运算符获得类的类型
// object.GetType()获取对象的类型做比较
if(item.GetType() == typeof(Item))
{
    Console.WriteLine("类型一致");
}
else
{
    Console.WriteLine("类型不一致");
}

// 序列化 将数据转化为文本
string Serialize(object obj)
{
    Type type = obj.GetType();
    string res = "";
    //BindingFlags flag =  BindingFlags.NonPublic |  BindingFlags.Instance | BindingFlags.Public;

    // 获取字段(成员变量)
    //FieldInfo[] fieldInfo = type.GetFields(flag);
    //foreach (FieldInfo field in fieldInfo)
    //{
    //    res += $"{field.Name}:{field.GetValue(obj)}\n";
    //}

    // 获取属性
    PropertyInfo[] propertyInfo = type.GetProperties();
    //propertyInfo.Select
    foreach (PropertyInfo property in propertyInfo)
    {
        var attr = property.GetCustomAttribute<ShowAttribute>();
        if (attr != null)
        {
            // 如果获取到了这个特性(标签)
            if (attr.Show)
            {
                res += $"{property.Name}:{property.GetValue(obj)} by {attr.Author()}\n";
            }
        }
        
    }

    // 修改内容
    //PropertyInfo? property = type.GetProperty("Id");
    //property?.SetValue(obj, 123);

    // 获取方法
    //MethodInfo[] methodInfos = type.GetMethods(flag);
    //MethodInfo? method = type.GetMethod("Test",flag);
    //method?.Invoke(obj, null);

    // 生成对象
    //var instance = Activator.CreateInstance(type,233,"新道具","动态创建的");
    //(instance as Item)?.Test();

    return res;
}

#region 位开关
int a = 1, b = 2;

a = a ^ b; // a = a ^ b;
b = a ^ b; // a = a ^ b ^ b = a ^ 0 = a
a = a ^ b; // a = a ^ a ^ b = 0 ^ b = b

TestEnum res = TestEnum.A | TestEnum.C | TestEnum.E; // 按位或(打开开关) 加法
res = res^TestEnum.C;
// 位开关与自身按位与(检测开关)之后结果不变 说明测试位开关开启 反之则说明测试位开关未开启
// 其实就是在测试位开关中包不包含自身
Console.WriteLine(res);
if ((res & TestEnum.C) == TestEnum.C)
{
    // 处理如果开关B打开的事件
}
// 按位异或(关闭开关) 减法

enum TestEnum
{
    A = 1<<0,
    B = 1<<1,
    C = 1<<2,
    D = 1<<3,
    E = 1<<4,
    F = 1<<5,
    G = 1<<6,
}
// 按位或 打开开关
// 0000 0001
// 0000 0100
// 0000 0101
// 0001 0000

// 按位与 检测开关
// 0001 0101
// 0000 0001
// 0000 0001

// 按位异或 关闭开关
// 相同为false 不同为true
// 0001 0101
// 0000 0100
// 0001 0001

// 0000 0000
// 0000 0001 1
// 0000 0010 2
// 0000 0100 4
// 0000 1000 8
// 0001 0000 16
// 0010 0000 32
// 0100 0000 64
#endregion

// 特性 必须继承自Attribute 且名称后面必须带Attribute
// 但是使用的时候用[]写在要修饰的对象前 可以省略Attribute
// 它只对后面的一个对象生效
// 想要限制特性的修饰对象 可以为特性加上特性[AttributeUsage]

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
class ShowAttribute : Attribute
{
    public bool Show { get; set; }
    public string Tag { get; set; }
    public ShowAttribute(bool b)
    {
        Show = b;
    }

    public string Author()
    {
        return "刘";
    }

    
}
class Test
{

}

class Test1 : Test
{

}

class Test2 : Test1
{

}